package com.shchekoldin.juliet.packager.core;

import com.shchekoldin.juliet.packager.plugins.*;
import com.shchekoldin.juliet.packager.utils.FilesIterator;
import com.shchekoldin.juliet.packager.xml.GroupElement;
import com.shchekoldin.juliet.packager.xml.ProjectElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

public class Packager {

    private static Packager instance = null;

    private static final Logger logger = LoggerFactory.getLogger(Packager.class);

    private Class[] pluginsClasses = {
        PagesPreprocessor.class,
        LocalFileOptimizer.class,
        FilesAssembler.class,
        GlobalFilesOptimizer.class
    };

    private List<GroupElement> newGroups = new ArrayList<GroupElement>();

    // -------------------------------------------------------
    // -                      INSTANCE                       -
    // -------------------------------------------------------

    public static Packager getInstance() {
        if (instance == null) instance = new Packager();
        return instance;
    }

    private Packager() { }

    // -------------------------------------------------------
    // -                        LOGIC                        -
    // -------------------------------------------------------

    private void prepareGroups(List<GroupElement> groups) {
        for (GroupElement outerGroup : groups) {
            if ((outerGroup.getParentName() == null) || (outerGroup.getParent() != null)) {
                continue;
            }

            for (GroupElement innerGroup : groups) {
                if (innerGroup.getName().equals(outerGroup.getParentName())) {
                    outerGroup.setParent(innerGroup);
                    break;
                }
            }
        }
    }

    private void processGroup(GroupElement currentGroup) {
        if (currentGroup.isAbstract()) return;

        logger.info("Processing group {}", currentGroup.getName());

        FilesIterator filesIterator = new FilesIterator(currentGroup);

        for (Class pluginClass : pluginsClasses) {
            PackagerPlugin plugin = null;

            try {
                plugin = (PackagerPlugin) pluginClass.newInstance();
            } catch (InstantiationException e) {
                logger.error("Can't create plugin", e);
                exit();
            } catch (IllegalAccessException e) {
                logger.error("Can't create plugin", e);
                exit();
            }

            plugin.initialize(filesIterator);
        }

        filesIterator.run();
    }

    private void processGroups(List<GroupElement> groups) {
        for (GroupElement group : groups) {
            processGroup(group);
        }

        logger.info("{} new groups were added", newGroups.size());

        for (GroupElement group : newGroups) {
            processGroup(group);
        }
    }

    //
    // API
    //

    public void exit() {
        System.exit(1);
    }

    public void addNewGroup(GroupElement group) {
        newGroups.add(group);
    }

    public void run(String[] args) {
        logger.info("Juliet packager started");

        ProjectElement project = ProjectFactory.getInstance().run(args);

        List<GroupElement> groups = project.getGroups();

        logger.info("{} groups were found in specified project file", groups.size());

        prepareGroups(groups);
        processGroups(groups);

        logger.info("Juliet packager finished");
    }

}
